{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "outputs": [],
   "source": [
    "from typing import Annotated\n",
    "\n",
    "#from langchain_anthropic import ChatAnthropic\n",
    "from langchain_my_tools import bocha_tool\n",
    "from customize.get_ollama import GetOllama\n",
    "#from langchain_community.tools.tavily_search import TavilySearchResults\n",
    "from typing_extensions import TypedDict\n",
    "\n",
    "from langgraph.checkpoint.memory import MemorySaver\n",
    "from langgraph.graph import StateGraph, START, END\n",
    "from langgraph.graph.message import add_messages\n",
    "from langgraph.prebuilt import ToolNode, tools_condition\n",
    "\n",
    "\n",
    "class State(TypedDict):\n",
    "    messages: Annotated[list, add_messages]\n",
    "    # This flag is new\n",
    "    ask_human: bool"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "outputs": [],
   "source": [
    "from pydantic import BaseModel\n",
    "\n",
    "\n",
    "class RequestAssistance(BaseModel):\n",
    "    \"\"\"Escalate the conversation to an expert. Use this if you are unable to assist directly or if the user requires support beyond your permissions.\n",
    "\n",
    "    To use this function, relay the user's 'request' so the expert can provide the right guidance.\n",
    "    \"\"\"\n",
    "\n",
    "    request: str"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "outputs": [],
   "source": [
    "tool = bocha_tool\n",
    "tools = [tool]\n",
    "#llm = ChatAnthropic(model=\"claude-3-5-sonnet-20240620\")\n",
    "llm = GetOllama(model_type=1)()\n",
    "llm_with_tools = llm.bind_tools(tools +  [RequestAssistance])\n",
    "\n",
    "def chatbot(state: State):\n",
    "    response = llm_with_tools.invoke(state[\"messages\"])\n",
    "    ask_human = False\n",
    "    if (\n",
    "        response.tool_calls\n",
    "        and response.tool_calls[0][\"name\"] == RequestAssistance.__name__\n",
    "    ):\n",
    "        ask_human = True\n",
    "    return {\"messages\": [response], \"ask_human\": ask_human}"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "outputs": [
    {
     "data": {
      "text/plain": "<langgraph.graph.state.StateGraph at 0x298b3a1fac0>"
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "graph_builder = StateGraph(State)\n",
    "\n",
    "graph_builder.add_node(\"chatbot\", chatbot)\n",
    "graph_builder.add_node(\"tools\", ToolNode(tools=[tool]))"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "outputs": [
    {
     "data": {
      "text/plain": "<langgraph.graph.state.StateGraph at 0x298b3a1fac0>"
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain_core.messages import AIMessage, ToolMessage\n",
    "\n",
    "\n",
    "def create_response(response: str, ai_message: AIMessage):\n",
    "    return ToolMessage(\n",
    "        content=response,\n",
    "        tool_call_id=ai_message.tool_calls[0][\"id\"],\n",
    "    )\n",
    "\n",
    "\n",
    "def human_node(state: State):\n",
    "    new_messages = []\n",
    "    if not isinstance(state[\"messages\"][-1], ToolMessage):\n",
    "        # Typically, the user will have updated the state during the interrupt.\n",
    "        # If they choose not to, we will include a placeholder ToolMessage to\n",
    "        # let the LLM continue.\n",
    "        new_messages.append(\n",
    "            create_response(\"No response from human.\", state[\"messages\"][-1])\n",
    "        )\n",
    "    return {\n",
    "        # Append the new messages\n",
    "        \"messages\": new_messages,\n",
    "        # Unset the flag\n",
    "        \"ask_human\": False,\n",
    "    }\n",
    "\n",
    "\n",
    "graph_builder.add_node(\"human\", human_node)"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "outputs": [
    {
     "data": {
      "text/plain": "<langgraph.graph.state.StateGraph at 0x298b3a1fac0>"
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def select_next_node(state: State):\n",
    "    if state[\"ask_human\"]:\n",
    "        return \"human\"\n",
    "    # Otherwise, we can route as before\n",
    "    return tools_condition(state)\n",
    "\n",
    "\n",
    "graph_builder.add_conditional_edges(\n",
    "    \"chatbot\",\n",
    "    select_next_node,\n",
    "    {\"human\": \"human\", \"tools\": \"tools\", END: END},\n",
    ")"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "outputs": [],
   "source": [
    "# The rest is the same\n",
    "graph_builder.add_edge(\"tools\", \"chatbot\")\n",
    "graph_builder.add_edge(\"human\", \"chatbot\")\n",
    "graph_builder.add_edge(START, \"chatbot\")\n",
    "memory = MemorySaver()\n",
    "graph = graph_builder.compile(\n",
    "    checkpointer=memory,\n",
    "    # We interrupt before 'human' here instead.\n",
    "    interrupt_before=[\"human\"],\n",
    ")"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "outputs": [
    {
     "data": {
      "image/jpeg": "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fp6km0/mspg8vpeLCsuYii+22vZZdfIRMGAmNpZKDzu83zT16INwREQFV8ftiNeZGizZtfJVW5BjB6JmOEcx/sIdB0HpDj3lWhVgjx3iUxzNy3HYlzJDt03sTNLRv69qxJHo3HrC6ML+6J0W/wDOdlhZ0RFzoIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiCv5mhYx2VbncfD4xL2QguVWnzp4WkuaWejtGFztgehDnDpuCPDJ4jS/FPT3iuToY/UmIdIHOrXYGzRtkb6HMePNe3fqCAQe8BWNQmV0bistdN18MlXIEAG7SmfXmcB3BzmEF4HqduOp6LfFVNcRFerX1XTpVNvg3cKWBwbw40u0PGzgMTB1G4Ox831gf4Lv0/wM4d6TzFbLYXQ+n8Tk6xJhuU8bFFLGSC08rmtBG4JH9hKkDoiYABmp88xo9HbxO/5mMlPImx7VZ766H+Er+Hh7/KS0bVoRVfyJse1We+uh/hKp8VcfldG6ByuYx2qcwblYRmMTywlnnSsadx2Y9Dj6U/Dw9/lJaNrVF+EBwII3B7wqx5E2ParPfXQ/wk8ibHtVnvrof4Sfh4e/yktG1Xv/Vr4T/9W2lf+EQfur9Pg2cJ3Ek8N9LEnvJxMBJ/8KsHkTY9qs99dD/CX6NDueOWfUWdsM67t8bEW4P542tP+BTIw9/lJaNrvy2eq4PsKMDG2MjK3arjoSA9wHTcj+jGPS89B/aQD5adwz8TWnksvZNkbkvjFuZgPK6QgDZu/Xla1rWj8zRv1JXswunMbp6OVmPqMrmUh0su5dJKR0Be9xLnnb0uJKkljVVTEZNGj9zyERFpQREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQFnvH8gcIs/uSBtB3f9vH+cLQlnvH/f8EWf2232g+Ntt/p4/Wg0JERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQFnnhAjfhDqDqG9IOpHT/TxrQ1nnhA7fgh1Bv0G0Ho3/18aDQ0REBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQERE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D4czPsZm/raX3lPhzM+xmb+tpfeVf0TvUbkc+pfgqGExGQymbrZXJU3YuKm17a1SSRr5XPeNi95Y4tADdwACT5xJI7lb0Rc2JiTiTeSZuIiLUgiIgIiICIiAiIgIiICIiAiIgIiII7UcL7GnspFG0ukfVla1o9JLCAq1pd7ZNNYlzTu11SEg+scgV2VTtcPm9vI/GZvJYOF7i81aYgfCHHqS1ssT+Xc9dmkDck7dV24OJTFM0VTbWuqzpRcHkBkPbPN/UUvu6eQGQ9s839RS+7rffD3459C3F3ouDyAyHtnm/qKX3dPIDIe2eb+opfd0vh78c+hbi70XB5AZD2zzf1FL7unkBkPbPN/UUvu6Xw9+OfQtxd6Lg8gMh7Z5v6il93TyAyHtnm/qKX3dL4e/HPoW4u9FweQGQ9s839RS+7p5AZD2zzf1FL7ul8Pfjn0LcXei4PIDIe2eb+opfd08gMh7Z5v6il93S+Hvxz6FuLvRcHkBkPbPN/UUvu6eQGQ9s839RS+7pfD3459C3F3ouDyAyHtnm/qKX3dPIDIe2eb+opfd0vh78c+hbi70XB5AZD2zzf1FL7uvJmgbm5Eurs1Mw97ezqM36+tsAI/uPpUvh78c+hbi/eH7CL2rZQd2S5cFp2PoqVmH/wATXD+5W9cmKxVXCY+GlShEFaIENbuXEkkkuJO5c4kklxJJJJJJJXWuLGrjErmqNHTMTnERFpQREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERB//9k=",
      "text/plain": "<IPython.core.display.Image object>"
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from IPython.display import display, Image\n",
    "\n",
    "try:\n",
    "    img = Image(graph.get_graph().draw_mermaid_png())\n",
    "    display(Image)\n",
    "except Exception:\n",
    "    # This requires some extra dependencies and is optional\n",
    "    pass"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "================================\u001B[1m Human Message \u001B[0m=================================\n",
      "\n",
      "I need some expert guidance for building this AI agent. Could you request assistance for me?\n",
      "==================================\u001B[1m Ai Message \u001B[0m==================================\n",
      "Tool Calls:\n",
      "  RequestAssistance (f4b42fd4-8ce5-437e-92a4-c7badbb093b9)\n",
      " Call ID: f4b42fd4-8ce5-437e-92a4-c7badbb093b9\n",
      "  Args:\n",
      "    request: I need some expert guidance for building this AI agent.\n"
     ]
    }
   ],
   "source": [
    "user_input = \"I need some expert guidance for building this AI agent. Could you request assistance for me?\"\n",
    "config = {\"configurable\": {\"thread_id\": \"1\"}}\n",
    "# The config is the **second positional argument** to stream() or invoke()!\n",
    "events = graph.stream(\n",
    "    {\"messages\": [(\"user\", user_input)]}, config, stream_mode=\"values\"\n",
    ")\n",
    "for event in events:\n",
    "    if \"messages\" in event:\n",
    "        event[\"messages\"][-1].pretty_print()"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "outputs": [
    {
     "data": {
      "text/plain": "('human',)"
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "snapshot = graph.get_state(config)\n",
    "snapshot.next"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "content='' additional_kwargs={} response_metadata={'model': 'qwen2.5', 'created_at': '2024-11-10T12:46:45.4658629Z', 'message': {'role': 'assistant', 'content': '', 'tool_calls': [{'function': {'name': 'RequestAssistance', 'arguments': {'request': 'I need some expert guidance for building this AI agent.'}}}]}, 'done_reason': 'stop', 'done': True, 'total_duration': 2349231500, 'load_duration': 1647984700, 'prompt_eval_count': 288, 'prompt_eval_duration': 187930000, 'eval_count': 31, 'eval_duration': 510125000} id='run-8c63ce15-abfa-4df1-9f75-44aed7f75a3d-0' tool_calls=[{'name': 'RequestAssistance', 'args': {'request': 'I need some expert guidance for building this AI agent.'}, 'id': 'f4b42fd4-8ce5-437e-92a4-c7badbb093b9', 'type': 'tool_call'}] usage_metadata={'input_tokens': 288, 'output_tokens': 31, 'total_tokens': 319}\n"
     ]
    },
    {
     "data": {
      "text/plain": "{'configurable': {'thread_id': '1',\n  'checkpoint_ns': '',\n  'checkpoint_id': '1ef9f624-0f61-667e-8002-4f425cca3bd2'}}"
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ai_message = snapshot.values[\"messages\"][-1]\n",
    "print(ai_message)\n",
    "human_response = (\n",
    "    \"We, the experts are here to help! We'd recommend you check out LangGraph to build your agent.\"\n",
    "    \" It's much more reliable and extensible than simple autonomous agents.\"\n",
    ")\n",
    "tool_message = create_response(human_response, ai_message)\n",
    "graph.update_state(config, {\"messages\": [tool_message]})"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "outputs": [
    {
     "data": {
      "text/plain": "[HumanMessage(content='I need some expert guidance for building this AI agent. Could you request assistance for me?', additional_kwargs={}, response_metadata={}, id='2aa185ef-3a91-475e-affd-69b693880a87'),\n AIMessage(content='', additional_kwargs={}, response_metadata={'model': 'qwen2.5', 'created_at': '2024-11-10T12:46:45.4658629Z', 'message': {'role': 'assistant', 'content': '', 'tool_calls': [{'function': {'name': 'RequestAssistance', 'arguments': {'request': 'I need some expert guidance for building this AI agent.'}}}]}, 'done_reason': 'stop', 'done': True, 'total_duration': 2349231500, 'load_duration': 1647984700, 'prompt_eval_count': 288, 'prompt_eval_duration': 187930000, 'eval_count': 31, 'eval_duration': 510125000}, id='run-8c63ce15-abfa-4df1-9f75-44aed7f75a3d-0', tool_calls=[{'name': 'RequestAssistance', 'args': {'request': 'I need some expert guidance for building this AI agent.'}, 'id': 'f4b42fd4-8ce5-437e-92a4-c7badbb093b9', 'type': 'tool_call'}], usage_metadata={'input_tokens': 288, 'output_tokens': 31, 'total_tokens': 319}),\n ToolMessage(content=\"We, the experts are here to help! We'd recommend you check out LangGraph to build your agent. It's much more reliable and extensible than simple autonomous agents.\", id='2690e69c-754d-43b1-88c6-4be2818ee3c3', tool_call_id='f4b42fd4-8ce5-437e-92a4-c7badbb093b9')]"
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "graph.get_state(config).values[\"messages\"]"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "=================================\u001B[1m Tool Message \u001B[0m=================================\n",
      "\n",
      "We, the experts are here to help! We'd recommend you check out LangGraph to build your agent. It's much more reliable and extensible than simple autonomous agents.\n",
      "=================================\u001B[1m Tool Message \u001B[0m=================================\n",
      "\n",
      "We, the experts are here to help! We'd recommend you check out LangGraph to build your agent. It's much more reliable and extensible than simple autonomous agents.\n",
      "==================================\u001B[1m Ai Message \u001B[0m==================================\n",
      "\n",
      "Great advice! According to our experts, you might want to consider using LangGraph for building your AI agent. They say it's both more reliable and more extensible compared to simpler solutions.\n",
      "\n",
      "Would you like some assistance in setting up LangGraph or do you have any other questions?\n"
     ]
    }
   ],
   "source": [
    "events = graph.stream(None, config, stream_mode=\"values\")\n",
    "for event in events:\n",
    "    if \"messages\" in event:\n",
    "        event[\"messages\"][-1].pretty_print()"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [],
   "metadata": {
    "collapsed": false
   }
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
